using System;
using System.Collections.Generic;
using OneDayModel.Interfaces;
using OneDayModel.Model;
using OneDayModel.Model.Repository;
using OneDayModel.Services;
using OneDayModel.Tests.Fits.Fixtures.Definitions;
using OneDayModel.Tests.Fits.Fixtures.Query;
using TestUtils;

namespace OneDayModel.Tests.Mocks
{
    public class MockRepository : IRepository, IOnlineCache
    {
        private readonly ConfirmationServices confirmationServices;

        private readonly Dictionary<string, IRoleAttribute> roleAttributesDictionary =
            new Dictionary<string, IRoleAttribute>();

        private readonly Dictionary<string, List<IAlbum>> albums = new Dictionary<string, List<IAlbum>>();

        public MockRepository()
        {
            confirmationServices =
                new ConfirmationServices(this, new MockMailSender(), new MockMailComposer(), new MockIdGenerator());
            ContextManager.TestContext[typeof (ConfirmationServices).Name] = confirmationServices;
            CreateRoleAttributesDictionary();
        }

        #region IRepository Members

        public IList<IRole> GetRoles()
        {
            List<IRole> rawResult = new List<IRole>();

            DefinitionExplorer<RolesDefinitionFixture> roleDefinitions =
                new DefinitionExplorer<RolesDefinitionFixture>();
            for (int i = 0; i < roleDefinitions.Count; i++)
            {
                rawResult.Add(new Role(roleDefinitions[i].Name,
                                       roleDefinitions[i].Public == "yes" ? true : false,
                                       roleDefinitions[i].ParentRole,
                                       BuildRoleAttributes(roleDefinitions[i].Attributes)));
            }

            return rawResult;
        }

        public IUser NewUser()
        {
            return new User(this, confirmationServices);
        }

        public void CreateUser(string alias, string email, string password, IEnumerable<IRole> assignedRoles,
                               IEnumerable<KeyValuePair<string, string>> attributes, AccountStatus userAccountStatus)
        {
            UserDefinitionFixture userDefinitionFixture = new UserDefinitionFixture();
            userDefinitionFixture.RegisterFixture();
            userDefinitionFixture.Alias = alias;
            userDefinitionFixture.AccountStatus = userAccountStatus.ToString();
            string excludeFromList = "Alias;eMail;Password;AccountStatus";
            foreach (KeyValuePair<string, string> attribute in attributes)
            {
                if (excludeFromList.Contains(attribute.Key) == false)
                {
                    if (!string.IsNullOrEmpty(userDefinitionFixture.Attributes))
                        userDefinitionFixture.Attributes += ";";
                    userDefinitionFixture.Attributes += string.Format("{0}={1}", attribute.Key, attribute.Value);
                }
            }
            userDefinitionFixture.eMail = email;
            userDefinitionFixture.Password = password;
            foreach (Role assignedRole in assignedRoles)
            {
                if (assignedRole.Public)
                {
                    if (!string.IsNullOrEmpty(userDefinitionFixture.Roles))
                        userDefinitionFixture.Roles += ";";
                    userDefinitionFixture.Roles += assignedRole.Name;
                }
            }
            userDefinitionFixture.CreationDate =
                GetCurrentTime().GetValueOrDefault(new DateTime(1900, 1, 1)).ToString("yyy-MM-dd");
            userDefinitionFixture.execute();
        }

        public void RegisterConfirmationSent(string alias, string confirmationId)
        {
            PendingConfirmationsDefinitionFixture confirmationsDefinitionFixture =
                new PendingConfirmationsDefinitionFixture();
            confirmationsDefinitionFixture.RegisterFixture();
            confirmationsDefinitionFixture.UserAlias = alias;
            confirmationsDefinitionFixture.ConfirmationId = confirmationId;
            confirmationsDefinitionFixture.execute();
        }

        public IUser GetUserPendingForConfirmation(string confirmationId)
        {

            DefinitionExplorer<PendingConfirmationsDefinitionFixture> pendingConfirmationsExplorer =
                new DefinitionExplorer<PendingConfirmationsDefinitionFixture>();

            for (int i = 0; i < pendingConfirmationsExplorer.Count; i++)
            {
                if (pendingConfirmationsExplorer[i].ConfirmationId == confirmationId)
                    return GetUserByAlias(pendingConfirmationsExplorer[i].UserAlias);
            }

            return null;
        }

        public void UpdateUser(string alias, List<KeyValuePair<string, string>> changes)
        {
            IDictionary<string, IList<string>> userDefinitions = UsersQueryFixture.GetUserDefinitions();
            int index;
            if (GetUserDefinitionIndexByAlias(userDefinitions, alias, out index))
            {
                foreach (KeyValuePair<string, string> change in changes)
                {
                    userDefinitions[change.Key][index] = change.Value;
                }
            }
        }

        public void RegisterConfirmationDone(string confirmationId)
        {
            IDictionary<string, IList<string>> pendingConfirmations =
                PendingConfirmationsQueryFixture.GetPendingConfirmations();
            int index;
            if (GetPendingConfirmationIndexByConfirmationId(pendingConfirmations, confirmationId, out index))
            {
                pendingConfirmations["UserAlias"].RemoveAt(index);
                pendingConfirmations["ConfirmationId"].RemoveAt(index);
            }
        }


        public bool IsAliasUnique(string alias)
        {
            DefinitionExplorer<UserDefinitionFixture> userDefinitions = new DefinitionExplorer<UserDefinitionFixture>();
            for (int i = 0; i < userDefinitions.Count; i++)
            {
                if (userDefinitions[i].Alias == alias)
                    return false;
            }
            return true;
        }

        public IUser GetUserByEmail(string email)
        {
            DefinitionExplorer<UserDefinitionFixture> userDefinitions = new DefinitionExplorer<UserDefinitionFixture>();
            for (int i = 0; i < userDefinitions.Count; i++)
            {
                if (userDefinitions[i].eMail == email)
                {
                    return
                        new User(this, confirmationServices, userDefinitions[i].Password, userDefinitions[i].Alias,
                                 userDefinitions[i].eMail, userDefinitions[i].AccountStatus);
                }
            }
            return null;
        }

        #endregion

        private IEnumerable<IRoleAttribute> BuildRoleAttributes(string roleAttributesString)
        {
            List<IRoleAttribute> attributes = new List<IRoleAttribute>();
            string[] attrs = roleAttributesString.Split(';');
            foreach (string attr in attrs)
            {
                attributes.Add(roleAttributesDictionary[attr]);
            }
            return attributes;
        }

        private void CreateRoleAttributesDictionary()
        {
            DefinitionExplorer<AttributesDefinitionFixture> attributesDefinitions =
                new DefinitionExplorer<AttributesDefinitionFixture>();
            for (int i = 0; i < attributesDefinitions.Count; i++)
            {
                string name = attributesDefinitions[i].Name;
                roleAttributesDictionary.Add(name, new RoleAttribute(name,
                                                                     attributesDefinitions[i].DisplayName,
                                                                     attributesDefinitions[i].Required == "yes",
                                                                     attributesDefinitions[i].Visible == "yes",
                                                                     Type.GetType(attributesDefinitions[i].Type),
                                                                     attributesDefinitions[i].ValuesRange.Split(';')
                                                       ));
            }
        }

        private bool GetUserDefinitionIndexByAlias(IDictionary<string, IList<string>> userDefinitions, string alias,
                                                   out int index)
        {
            int count = userDefinitions["Alias"].Count;
            index = -1;
            for (int i = 0; i < count; i++)
            {
                if (userDefinitions["Alias"][i] == alias)
                {
                    index = i;
                    break;
                }
            }
            return (index > -1) && (index < count);
        }

        private bool GetPendingConfirmationIndexByConfirmationId(
            IDictionary<string, IList<string>> pendingConfirmations, string confirmationId, out int index)
        {
            int count = pendingConfirmations["UserAlias"].Count;
            index = -1;
            for (int i = 0; i < count; i++)
            {
                if (pendingConfirmations["ConfirmationId"][i] == confirmationId)
                {
                    index = i;
                    break;
                }
            }
            return (index > -1) && (index < count);
        }

        public IUser GetUserByAlias(string alias)
        {
            DefinitionExplorer<UserDefinitionFixture> userDefinitions =
                new DefinitionExplorer<UserDefinitionFixture>();
            for (int i = 0; i < userDefinitions.Count; i++)
            {
                if (userDefinitions[i].Alias == alias)
                {
                    IUser user = new User(this, confirmationServices, userDefinitions[i].Password, userDefinitions[i].Alias,
                                         userDefinitions[i].eMail, userDefinitions[i].AccountStatus);

                    if (!String.IsNullOrEmpty(userDefinitions[i].Albums))
                    {
                        string albumsData = userDefinitions[i].Albums;
                        string[] userAlbums = albumsData.Split(';');
                        foreach (string album in userAlbums)
                        {
                            if (!String.IsNullOrEmpty(album))
                            {
                                string[] split = album.Split('=');
                                IAlbum albumObject = new Album(split[0]);
                                if (!String.IsNullOrEmpty(split[1]))
                                {
                                    string[] pictures = split[1].Split(',');
                                    foreach (string picture in pictures)
                                    {
                                        albumObject.AddPicture(picture);
                                    }
                                }

                                RegisterAlbum(user, split[0]);
                                user.AddAlbum(albumObject);
                            }
                        }
                    }
                    return user;
                }
            }
            
            return null;
        }

        public StatisticsStruct CollectStatistics()
        {
            DateTime? curentTime = GetCurrentTime();
            Dictionary<string, TempStatistic> result = new Dictionary<string, TempStatistic>();
            DefinitionExplorer<UserDefinitionFixture> userDefinitions =
                new DefinitionExplorer<UserDefinitionFixture>();
            for (int i = 0; i < userDefinitions.Count; i++)
            {
                if (userDefinitions[i].AccountStatus == AccountStatus.existAndActive.ToString())
                {
                    string[] userRoles = userDefinitions[i].Roles.Split(';');
                    foreach (string userRole in userRoles)
                    {
                        TempStatistic value;
                        if (!result.TryGetValue(userRole, out value))
                        {
                            value = new TempStatistic();
                            result.Add(userRole, value);       
                        }
                        value.Totals++;
                        if (userDefinitions[i].Online.ToLower() == "yes")
                            value.Online++;
                        DateTime userCreationDate = DateTime.Parse(userDefinitions[i].CreationDate);
                        if (userCreationDate.Date.Equals(curentTime.GetValueOrDefault(new DateTime(1900, 1, 1)).Date))
                            value.NewToday++;

                    }
                }
            }
            List<Statistic> totals = new List<Statistic>();
            List<Statistic> online = new List<Statistic>();
            List<Statistic> newToday = new List<Statistic>();
            foreach (KeyValuePair<string, TempStatistic> pair in result)
            {
                totals.Add(new Statistic(pair.Key, pair.Value.Totals));
                online.Add(new Statistic(pair.Key, pair.Value.Online));
                newToday.Add(new Statistic(pair.Key, pair.Value.NewToday));
            }
            return new StatisticsStruct(totals, online, newToday);
        }

        public IAlbum RegisterAlbum(IUser user, string albumName)
        {
            IAlbum album = new Album(albumName);
            string userAlias = user["Alias"];

            if (!albums.ContainsKey(userAlias))
                albums.Add(userAlias, new List<IAlbum>());

            albums[userAlias].Add(album);

            return album;
        }

        public IAlbum GetAlbumForUser(string alias, string albumName)
        {
            if (albums.ContainsKey(alias))
            {
                IAlbum foundAlbum = null;
                albums[alias].ForEach(delegate(IAlbum album)
                                          {
                                              if (album.Name == albumName)
                                                  foundAlbum = album;
                                          });

                return foundAlbum;
            }

            return null;
        }

        public string GetBasePathForAlbums(string userAlias)
        {
            return @"\" + userAlias;
        }

        public void RegisterPictureInAlbum(string userAlias, string albumName, string fileName)
        {
            IAlbum album = GetAlbumForUser(userAlias, albumName);
            album.AddPicture(fileName);

            AlbumsRepositoryDefinitionFixture albumsRepositoryDefinitionFixture = new AlbumsRepositoryDefinitionFixture();
            
            albumsRepositoryDefinitionFixture.RegisterFixture();
            albumsRepositoryDefinitionFixture.Alias = userAlias;
            albumsRepositoryDefinitionFixture.Album = albumName;
            albumsRepositoryDefinitionFixture.Pictures = fileName;

            albumsRepositoryDefinitionFixture.execute();
        }

        private DateTime? GetCurrentTime()
        {
            DefinitionExplorer<EnvironmentDefinitionFixture> env = new DefinitionExplorer<EnvironmentDefinitionFixture>();
            if (env.Count > 0)
                return DateTime.Parse(env[0].CurrentDate);
            return null;
        }

        public class TempStatistic
        {
            public int Totals = 0;
            public int Online = 0;
            public int NewToday = 0;
        }

        public void RegisterUserOnline(string userAlias)
        {
            UpdateUser(userAlias, new List<KeyValuePair<string, string>>(new KeyValuePair<string,string>[1]{new KeyValuePair<string, string>("Online", "yes")}));
        }
    }
}